﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using MSH.Common.Classes;
using MSH.Common.DAO;

namespace MSH.Common.Helpers
{
    /// <summary>
    /// De helper is verantwoordelijk voor taken die samenhangen met de locatie.
    /// </summary>
    public static class LocationHelper
    {
        private static String _bingId;
        private static String _bingUrl;

        static LocationHelper()
        {
            _bingId = System.Configuration.ConfigurationManager.AppSettings["bingId"].ToString();
            _bingUrl = System.Configuration.ConfigurationManager.AppSettings["bingUrl"].ToString();
        }

        /// <summary>
        /// Geeft de tekstuele representatie van de input coördinaten.
        /// </summary>
        /// <param name="lat">Latitude</param>
        /// <param name="lng">Longitude</param>
        /// <returns>LocationData object met daarin de tekstuele representatie van de gespecificeerde coördinaten.</returns>
        public static UserLocationData GetLocationData(double lat, double lng)
        {
            UserLocationData locationData = new UserLocationData(lat, lng);

            String strPostString = string.Format("{0}/{1},{2}", _bingUrl, lat.ToString().Replace(',', '.'), lng.ToString().Replace(',', '.'));
            String strDataString = string.Format("o=xml&key={0}", _bingId);
       
            XmlTextReader xmlReader = new XmlTextReader(string.Format("{0}?{1}", strPostString, strDataString));

            while (xmlReader.Read())
            {
                if (xmlReader.NodeType == XmlNodeType.Element)
                {
                    switch (xmlReader.LocalName)
                    {
                        case "AddressLine":
                            {
                                locationData.AddressLine = xmlReader.ReadString();
                                break;
                            }
                        case "AdminDistrict":
                            {
                                locationData.AdminDistrict = xmlReader.ReadString();
                                break;
                            }
                        case "CountryRegion":
                            {
                                locationData.CountryRegion = xmlReader.ReadString();
                                break;
                            }
                        case "Locality":
                            {
                                locationData.Locality = xmlReader.ReadString();
                                break;
                            }
                        case "PostalCode":
                            {
                                locationData.PostalCode = xmlReader.ReadString();
                                break;
                            }
                    }
                }
            }
            return locationData;
        }

        /// <summary>
        /// Berekent de afstand tussen twee punten, gebruikmakend van de Haversine formule.
        /// 
        /// Haversine formula:
        /// R = earth’s radius (mean radius = 6371km)
        /// Δlat = lat2− lat1
        /// Δlong = long2− long1
        ///  a = sin²(Δlat/2) + cos(lat1).cos(lat2).sin²(Δlong/2)
        ///  c = 2.atan2(√a, √(1−a))
        ///  d = R.c 
        /// </summary>
        /// <param name="args">Latitude 1</param>
        /// <param name="args">Latitude 2</param>
        /// <param name="args">Longitude 1</param>
        /// <param name="args">Longitude 2</param>
        /// <returns>Afstand tussen de twee punten in kilometers</returns>
        public static double CalculateDistance(double lat1, double lat2, double lon1, double lon2)
        {
            var R = 6371; // km
            var dLat = (lat2-lat1)/180; //rad
            var dLon = (lon2-lon1)/180; //rad
            var a = Math.Sin(dLat/2) * Math.Sin(dLat/2) +   Math.Cos(lat1/180) * Math.Cos(lat2/180) * Math.Sin(dLon/2) * Math.Sin(dLon/2);
            var c = 2 * Math.Atan2(Math.Sqrt(a), Math.Sqrt(1-a));
            var d = R * c;

            return d;
        }
    }
}
